iT邦幫忙

2025 iThome 鐵人賽

DAY 26
1

這篇寫完就還剩五篇,今天來完成 HackMD 的 API 串接部份

AI 寫扣經過

  1. UserPreferencesRepository 增加儲存金鑰功能
    val hackmdApiKey: Flow<String> = context.dataStore.data
        .map { preferences ->
            preferences[Keys.hackmdApiKey] ?: ""
        }
    
    suspend fun setHackmdApiKey(apiKey: String) {
        context.dataStore.edit { preferences ->
            preferences[Keys.hackmdApiKey] = apiKey
        }
    }
    
    suspend fun clearHackmdApiKey() {
        context.dataStore.edit { preferences ->
            preferences.remove(Keys.hackmdApiKey)
        }
    }        
    
  2. 建立 use case
    class GetHackmdApiKeyUseCase @Inject constructor(
        private val repository: UserPreferencesRepository
    ) {
        operator fun invoke(): Flow<String> {
            return repository.hackmdApiKey
        }
    }
    class SaveHackmdApiKeyUseCase @Inject constructor(
        private val repository: UserPreferencesRepository
    ) {
        suspend operator fun invoke(apiKey: String) {
            repository.setHackmdApiKey(apiKey)
        }
    }
    class ClearHackmdApiKeyUseCase @Inject constructor(
        private val repository: UserPreferencesRepository
    ) {
        suspend operator fun invoke() {
            repository.clearHackmdApiKey()
        }
    }
    
  3. SettingsViewModel 注入 use case
    val uiState: StateFlow<SettingsUiState> = combine(
        getSettingsUseCase(),
        getHackmdApiKeyUseCase()
    ) { settings, apiKey ->
        SettingsUiState(
            settings = settings,
            hackmdApiKey = apiKey,
            isLoading = false
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = SettingsUiState(isLoading = true)
    )
    
    fun onHackmdApiKeyChanged(apiKey: String) {
        viewModelScope.launch {
            saveHackmdApiKeyUseCase(apiKey)
        }
    }
    
    fun onClearHackmdApiKey() {
        viewModelScope.launch {
            clearHackmdApiKeyUseCase()
        }
    }    
    
  4. SettingsScreenContent Composable 畫面加入 UI 元件
    Spacer(modifier = Modifier.height(16.dp))
    // HackMD Section
    Text(
        text = "HackMD 整合",
        style = MaterialTheme.typography.titleLarge
    )
    Button(onClick = { uriHandler.openUri("https://hackmd.io/") }) {
        Text("前往 HackMD 官網")
    }
    Button(onClick = { uriHandler.openUri("https://hackmd.io/@docs/issue-revoke-api-token-zh") }) {
        Text("如何取得 Token?")
    }
    val isApiKeySet = uiState.hackmdApiKey.isNotBlank()
    TextField(
        value = uiState.hackmdApiKey,
        onValueChange = onApiKeyChanged,
        label = { Text("HackMD API Token") },
        modifier = Modifier.fillMaxWidth(),
        readOnly = isApiKeySet,
        visualTransformation = if (isApiKeySet) PasswordVisualTransformation() else VisualTransformation.None,
        trailingIcon = {
            if (isApiKeySet) {
                IconButton(onClick = onClearApiKey) {
                    Icon(
                        imageVector = Icons.Default.Clear,
                        contentDescription = "清除 API Token"
                    )
                }
            }
        }
    )
    

上一篇
114/25 - Vibe Coding 建立設定頁
系列文
看見筆記捲土重來,試著用 Vibe Coding 完成一款 App 吧!26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chiaominchang222
iT邦新手 5 級 ‧ 2025-10-10 12:22:57

確實要另外存放 阿我還有六篇

我要留言

立即登入留言